using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace Shapes.Geometry
{
    /// <summary>
    /// A LineList is a container for Lines which are not connected
    /// </summary>
    public class LineList : Drawing, ILinedGeometry
    {
        /// <summary>
        /// All Lines stored in this LineList
        /// </summary>
        public List<Line> Lines { get { return lines; } }
        List<Line> lines = new List<Line>();


        public LineList(params Line[] lines)
        {
            foreach (Line l in lines)
                this.lines.Add(l);
        }

        /// <summary>
        /// Iterates through all Lines of the LineList
        /// </summary>
        /// <returns>every line the LineList contains</returns>
        public IEnumerable<Line> GetLines()
        {
            foreach (Line l in lines)
                yield return l;
        }

        /// <summary>
        /// The global position of the first lines start point
        /// </summary>
        public Vector2 StartPoint
        {
            get { return (lines.Count > 0) ? lines[0].StartPoint : new Vector2(); }
        }

        /// <summary>
        /// The amount of Lines in this LineList
        /// </summary>
        public int LineCount
        {
            get { return lines.Count; }
        }

        /// <summary>
        /// Gets the enumeration type which is mapped to this kind of object
        /// </summary>
        /// <returns>the geometry typee of this object</returns>
        public override GeometryType GetGeometryType()
        {
            return GeometryType.LineList;
        }

        internal override float GetDistanceToEdge(ref Vector2 point)
        {
            float min = float.MaxValue;

            foreach (Line l in lines)
            {
                float tmp = l.GetDistanceToEdge(ref point);
                if (tmp < min)
                    min = tmp;
            }
            return min;
        }

        internal override Vector2 GetNearestPointOnEdge(ref Vector2 point)
        {
            return GetClosestLine(ref point).GetNearestPointOnEdge(ref point);
        }

        private Line GetClosestLine(ref Vector2 point)
        {
            float min = float.MaxValue;
            Line closest = null;
            foreach (Line l in lines)
            {
                float tmp = l.GetDistanceToEdge(ref point);
                if (tmp < min)
                {
                    min = tmp;
                    closest = l;
                }
            }
            return closest;
        }

        internal override Vector2 GetPositionFromT(float t)
        {
            float scale = 1f / lines.Count;

            int idx = 0;
            while ((idx + 1) * scale < t)
                idx++;

            float min = idx * scale;
            t = t - min / scale;

            return lines[idx].GetPositionFromT(t);
        }

        internal override float GetEdgePathValueFromPoint(ref Vector2 point)
        {
            float scale = 1f / lines.Count;

            Line l = GetClosestLine(ref point);
            int idx = lines.IndexOf(l);

            return l.GetEdgePathValueFromPoint(ref point) * scale + idx * scale;
        }

        internal override Vector2 GetTangent(ref Vector2 position)
        {
            Line l = GetClosestLine(ref position);
            return l.GetTangent(ref position);
        }

        internal override Vector2 GetNormal(ref Vector2 position)
        {
            Line l = GetClosestLine(ref position);
            return l.GetNormal(ref position);
        }
        /// <summary>
        /// Clones the LineList.
        /// </summary>
        /// <returns>an object with the type LineList</returns>
        public override object Clone()
        {
            LineList list = new LineList();

            foreach (Line l in lines)
            {
                list.lines.Add((Line)l.Clone());
            }

            return list;
        }
    }
}
